package com.hwpt.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.hwpt.dto.user.ResetPasswordDTO;
import com.hwpt.dto.user.UserPwdLoginDTO;
import com.hwpt.dto.user.UserRegisterDTO;
import com.hwpt.dto.user.VerifyCodeDTO;
import com.hwpt.entity.UserBasicInfo;
import com.hwpt.exception.AuthException;
import com.hwpt.mapper.UserBasicInfoMapper;
import com.hwpt.service.UserAuthService;
import com.hwpt.service.UserInfoService;
import com.hwpt.service.VerificationCodeService;
import com.hwpt.utils.JwtUtil;
import com.hwpt.utils.SCryptUtil;
import com.hwpt.vo.user.UserAllInfoVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.hwpt.constant.ExceptionMessageConstant.*;
import static com.hwpt.constant.RedisKeyConstant.REGISTERED_PHONE_KEY_PREFIX;

@Service
@RequiredArgsConstructor
@Slf4j
public class UserAuthServiceImpl implements UserAuthService {

    private final UserInfoService userInfoService;
    private final VerificationCodeService verificationCodeService;
    private final SCryptUtil scryptUtil;
    private final JwtUtil jwtUtil;
    private final UserBasicInfoMapper userBasicInfoMapper;
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    @Transactional
    public void register(UserRegisterDTO userRegisterDTO) {
        String phone = userRegisterDTO.getPhone();

        // 验证码状态校验
        if (!verificationCodeService.isVerificationCodeVerified(phone)) {
            throw new AuthException(VERIFY_CODE_NOT_VERIFIED);
        }

        userInfoService.registerUser(userRegisterDTO);
    }

    @Override
    public UserAllInfoVO loginWithPwd(UserPwdLoginDTO userPwdLoginDTO) {
        String account = userPwdLoginDTO.getAccount();
        String inputPassword = userPwdLoginDTO.getPassword();

        UserBasicInfo user = userInfoService.getUserByHanWangId(account);
        if (user == null) {
            user = userInfoService.getUserByPhone(account);
        }

        if (user == null) {
            throw new AuthException(LOGIN_ACCOUNT_NOT_EXIST);
        }

        String hanWangId = user.getHanWangId();

        boolean passwordMatch = scryptUtil.verify(inputPassword, user.getPassword());
        if (!passwordMatch) {
            throw new AuthException(LOGIN_PASSWORD_ERROR);
        }

        String token = jwtUtil.createUserToken(hanWangId);
        UserAllInfoVO userAllInfoVO = userInfoService.getUserAllInfo(hanWangId);
        userAllInfoVO.setToken(token);

        return userAllInfoVO;
    }

    @Override
    public UserAllInfoVO loginWithSms(VerifyCodeDTO verifyCodeDTO) {

        UserBasicInfo userByPhone = userInfoService.getUserByPhone(verifyCodeDTO.getPhone());
        if (userByPhone == null) {
            throw new AuthException(LOGIN_ACCOUNT_NOT_EXIST);
        }

        String hanWangId = userByPhone.getHanWangId();
        String token = jwtUtil.createUserToken(hanWangId);
        UserAllInfoVO userAllInfoVO = userInfoService.getUserAllInfo(hanWangId);
        userAllInfoVO.setToken(token);

        return userAllInfoVO;

    }

    @Override
    public void resetPassword(ResetPasswordDTO resetPasswordDTO) {
        if (resetPasswordDTO.getPassword() == null) {
            throw new AuthException(VERIFY_CODE_EMPTY);
        }
        String phone = resetPasswordDTO.getPhone();
        UserBasicInfo userByPhone = userInfoService.getUserByPhone(phone);
        if (userByPhone == null) {
            throw new AuthException(LOGIN_ACCOUNT_NOT_EXIST);
        }
        Object cachedUnregistered = redisTemplate.opsForValue().get(REGISTERED_PHONE_KEY_PREFIX + phone);
        if (cachedUnregistered == null) {
            throw new AuthException(VERIFY_CODE_NOT_VERIFIED);
        }

        String hanWangId = userByPhone.getHanWangId();
        String password = resetPasswordDTO.getPassword();
        String newPassword = scryptUtil.encrypt(password);
        LambdaUpdateWrapper<UserBasicInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(UserBasicInfo::getHanWangId, hanWangId) // 设置条件：hanWangId = ?
                .set(UserBasicInfo::getPassword, newPassword); // 设置要更新的字段
        int update = userBasicInfoMapper.update(null, wrapper);
        if (update != 1) {
            throw new AuthException(RESET_PASSWORD_ERROR);
        }
        redisTemplate.delete(REGISTERED_PHONE_KEY_PREFIX + phone);
        log.info("重置密码成功，手机号：{}", phone);

    }
}